/*
 * Class for buffered evaluating a text.
 * Resultsets will be saved for fast evaluation with other parameters.
 *
 * Set params using setter
 * Use clearBuffer() to make new evaluation.
 *
 * @author Paul Wagner
 */
package complet.db.genetics;

import complet.db.Evaluator;
import complet.db.Word;
import complet.helper.ConfigHelper;
import complet.helper.IOHelper;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeMap;

public class BufferedEvaluator extends Evaluator {

    private int sort = 1;
    private int[] p = new int[4];
    private Retrieval ret = null;
    private HashMap<String, TreeMap<String, Word>> buffer1 = new HashMap<String, TreeMap<String, Word>>();
    private HashMap<String, TreeMap<String, Word>> buffer2 = new HashMap<String, TreeMap<String, Word>>();
    private HashMap<String, TreeMap<String, Word>> buffer3 = new HashMap<String, TreeMap<String, Word>>();
    private HashMap<String, TreeMap<String, Word>> buffer4 = new HashMap<String, TreeMap<String, Word>>();
    private TreeMap<String, Word> res = null;
    private TreeMap<String, Word> _res = null;
    // COMPARATORS
    private final Comparator<String> COMP_CNT = new Comparator<String>() {

        public int compare(String s1, String s2) {
            //return res.get(s2).getSUM_COUNT().compareTo(res.get(s1).getSUM_COUNT());
            if (_res.get(s1).getSUM_COUNT() > _res.get(s2).getSUM_COUNT()) {
                return -1;
            }
            if (_res.get(s1).getSUM_COUNT() < _res.get(s2).getSUM_COUNT()) {
                return 1;
            }
            int _return = _res.get(s1).getWORD().compareTo(_res.get(s2).getWORD());
            if (_return != 0) {
                return _return;
            }
            return 1;
        }
    };
    private final Comparator<String> COMP_REL = new Comparator<String>() {

        public int compare(String s1, String s2) {
            //return res.get(s2).getAVG_RELLOC().compareTo(res.get(s1).getAVG_RELLOC());
            if (_res.get(s1).getAVG_REL() > _res.get(s2).getAVG_REL()) {
                return -1;
            }
            if (_res.get(s1).getAVG_REL() < _res.get(s2).getAVG_REL()) {
                return 1;
            }
            int _return = _res.get(s1).getWORD().compareTo(_res.get(s2).getWORD());
            if (_return != 0) {
                return _return;
            }
            return 1;
        }
    };

    // CONSTRUCTOR
    /*
     * Constructor using ConfigHelper, buffer database
     */
    public BufferedEvaluator() {
        this(ConfigHelper.DB_PATH, ConfigHelper.IN_PATH, ConfigHelper.MAX_RELATIONS, ConfigHelper.NAME_KEY, ConfigHelper.COUNT_KEY, ConfigHelper.CACHE_TYPE, ConfigHelper.BUFFER);
    }

    /*
     * Constructor using manual config values
     *
     */
    public BufferedEvaluator(String database, String in_path, int max_relations, String name_key, String count_key, String cache_type, Boolean buffer) {
        super(database, in_path, max_relations, name_key, count_key, cache_type, buffer, false);
        // Establish connection
        IOHelper.log("(BufferedEvaluator) New BufferedEvaluator");
        ret = new Retrieval(database, max_relations, name_key, count_key, cache_type, buffer);

        _res = new TreeMap<String, Word>();
        switch (sort) {
            case 0:
                res = new TreeMap<String, Word>(COMP_CNT);
                break;
            case 1:
                res = new TreeMap<String, Word>(COMP_REL);
                break;
            default:
                res = new TreeMap<String, Word>();
        }
    }

    // GETTER AND SETTER
    public int getSort() {
        return sort;
    }

    public void setSort(int sort) {
        this.sort = sort;
    }

    public int getP1() {
        return p[0];
    }

    @Override
    public void setP1(int p1) {
        this.p[0] = p1;
    }

    public int getP2() {
        return p[1];
    }

    @Override
    public void setP2(int p2) {
        this.p[1] = p2;
    }

    public int getP3() {
        return p[2];
    }

    @Override
    public void setP3(int p3) {
        this.p[2] = p3;
    }

    public int getP4() {
        return p[3];
    }

    @Override
    public void setP4(int p4) {
        this.p[3] = p4;
    }

    // METHODS
    @Override
    public void eval() {
        int _p = 0;
        cnt_0 = new int[2];
        cnt_1 = new int[2];
        cnt_2 = new int[2];
        cnt_3 = new int[2];
        loc_0 = new int[2];
        loc_1 = new int[2];
        loc_2 = new int[2];
        loc_3 = new int[2];

        if (buffer1.isEmpty()) {
            evalBuffer();
        }

        // Iterate buffers and then every resultset to add parameters
        // Write it to new resultset and sort it

        TreeMap<String, Word> r = null;
        TreeMap<String, Word> r2 = null;
        TreeMap<String, Word> r3 = null;
        TreeMap<String, Word> r4 = null;
        cnt_stnce = 0;

        for (String stnce : buffer1.keySet()) {
            res.clear();
            cnt_stnce++;

            if (cnt_stnce % 10000 == 9999) {
                IOHelper.log("####### (BufferedEvaluator) " + getP1() + ":" + getP2() + ":" + getP3() + ":" + getP4() + " RESULTS - STILL IN PROGRESS... ########");
                logResults();
            }

            // Get Resultsets for first sentence
            String org_word = stnce.split(" ")[4];

            // Iterate resultsets
            for (int i = 1; i < 5; i++) {
                switch (i) {
                    case 1:
                        r = buffer1.get(stnce);
                        _p = getP1();
                        break;
                    case 2:
                        r = buffer2.get(stnce);
                        _p = getP2();
                        break;
                    case 3:
                        r = buffer3.get(stnce);
                        _p = getP3();
                        break;
                    case 4:
                        r = buffer4.get(stnce);
                        _p = getP4();
                        break;
                    default:
                        r = null;
                }
                for (String word : r.keySet()) {
                    int cnt = 0;
                    int c_cnt = 0;
                    double relloc = 0;
                    double c_relloc = 0;

                    Word cur = r.get(word);
                    c_cnt = cur.getSUM_COUNT();
                    c_relloc = cur.getAVG_REL();

                    if (_res.containsKey(word)) {
                        cnt = _res.get(word).getSUM_COUNT();
                        relloc = _res.get(word).getAVG_REL();
                    }


                    Word new_word = new Word(cur.getNODE(), word, cnt + (c_cnt * _p), relloc + (c_relloc * _p), 0);
                    _res.put(word, new_word);
                    res.put(word, new_word);

                }
            }
            evalResult(res.keySet(), org_word);
        }
        IOHelper.log("####### (BufferedEvaluator) Params: " + getP1() + ":" + getP2() + ":" + getP3() + ":" + getP4() + " RESULTS - FINISHED... ########");
        logResults();
    }

    /*
     * Doing Evaluation and buffer
     *
     */
    private void evalBuffer() {
        IOHelper.log("(Evaluator) Start buffered evaluation");
        cnt_stnce = 0;
        String org_word = "";
        String stnce = "";

        while ((stnce = getNextLine()) != null) {
            cnt_stnce++;

            stnce = stnce.toLowerCase();        // LOWERCASE
            String[] words = stnce.split(" ");

            if (words.length >= 5) {
                String[] input = new String[4];
                System.arraycopy(words, 0, input, 0, 4);
                org_word = words[0 + 4];
                ret.setSentence(input, org_word.substring(0, 1));
            } else {
                continue;
            }

            // Make retrieval
            IOHelper.pln("Buffer sentence " + cnt_stnce);
            ret.eval();

            // Buffer Result
            buffer1.put(stnce, ret.getRes1());
            buffer2.put(stnce, ret.getRes2());
            buffer3.put(stnce, ret.getRes3());
            buffer4.put(stnce, ret.getRes4());
        }

    }

    private void evalResult(Set<String> set, String org_word) {
        int c;
        int[] t_1;
        int[] t_2;
        int[] t_3;

        switch (sort) {
            case 0:
                t_1 = cnt_1;
                t_2 = cnt_2;
                t_3 = cnt_3;
                break;
            case 1:
                t_1 = loc_1;
                t_2 = loc_2;
                t_3 = loc_3;
                break;
            default:
                return;
        }

        //1. anfangsbuchstabe vorgegeben
        c = 0;
        for (String key : set) {
            if (c++ >= 4) {
                break;
            }
            if (key.equals(org_word)) {
                if (c == 1) {
                    t_1[0]++;
                } else {
                    t_1[1]++;
                }
            }
        }


        //2. anfangsbuchstabe vorgegeben
        if (org_word.length() >= 3) {
            c = 0;
            for (String key : set) {
                if (key.length() < 2) {
                    continue;
                }
                if (!key.substring(0, 2).equals(org_word.substring(0, 2))) {
                    continue;
                }
                if (c++ >= 4) {
                    break;
                }
                if (key.equals(org_word)) {
                    //IOHelper.pln(_s + ":2 - Found a hit: " + key);
                    if (c == 1) {
                        t_2[0]++;
                    } else {
                        t_2[1]++;
                    }
                }
            }
        }

        //3. anfangsbuchstabe vorgegeben
        if (org_word.length() >= 4) {
            c = 0;
            for (String key : set) {
                if (key.length() < 3) {
                    continue;
                }
                if (!key.substring(0, 3).equals(org_word.substring(0, 3))) {
                    continue;
                }
                if (c++ >= 4) {
                    break;
                }
                if (key.equals(org_word)) {
                    if (c == 1) {
                        t_3[0]++;
                    } else {
                        t_3[1]++;
                    }
                }
            }
        }
    }

    public void clearBuffer() {
        buffer1.clear();
        buffer2.clear();
        buffer3.clear();
        buffer4.clear();
    }
}
